package com.weiyi.weiman.service.user.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.weiyi.weiman.domain.Const.ComicsConst;
import com.weiyi.weiman.domain.Const.ComicsIndexConst;
import com.weiyi.weiman.domain.Const.UserConst;
import com.weiyi.weiman.domain.dto.BrowseHistoryDTO;
import com.weiyi.weiman.domain.dto.CollectComicsDTO;
import com.weiyi.weiman.exception.APIException;
import com.weiyi.weiman.mapper.user.ComicsCollectMapper;
import com.weiyi.weiman.mapper.user.UserBrowseHistoryMapper;
import com.weiyi.weiman.service.comics.ComicsService;
import com.weiyi.weiman.service.user.UserComicsService;
import com.weiyi.weiman.service.user.UserService;
import com.weiyi.weiman.utils.FastDFSUtils;
import com.weiyi.weiman.utils.JWTUtils;
import com.weiyi.weiman.utils.RedisUtils;
import comics.Comics;
import comics.ComicsChapter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import user.ComicsCollect;
import user.UserBrowseHistory;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @Author zhang
 * @Date 2021/5/9 下午3:59
 * @Description 漫画指数的业务类
 * @Version 1.0
 **/
@Service
@Slf4j
public class UserComicsServiceImpl implements UserComicsService {

    @Autowired
    private UserBrowseHistoryMapper historyMapper;
    @Autowired
    private ComicsCollectMapper collectMapper;
    @Autowired
    private ComicsService comicsService;
    @Autowired
    private UserService userService;
    @Autowired
    private RedisUtils redisUtils;
    @Autowired
    private FastDFSUtils fastDFSUtils;

    /**
     * 漫画点赞
     * @param comicsId
     * @param token
     */
    @Override
    public Long giveLike(long comicsId, String token) {
        if (JWTUtils.validateJWT(token)) {
            String userId = JWTUtils.parseJWT(token).getSubject();
            //判断是否存在该用户
            userService.getUser(Long.parseLong(userId));
            //判断用户是否已经点赞，点赞过漫画的用户无法再次点赞
            String likeKey = ComicsIndexConst.LIKE_REDIS_PRE + comicsId;
            if (redisUtils.hExists(likeKey, userId)) {
                log.info("用户:{}已经点赞过漫画:{},无法多次点赞", userId, comicsId);
                throw new APIException("无法多次点赞");
            } else {
                log.info("用户:{}点赞成功漫画:{}", userId, comicsId);
                redisUtils.hPut(likeKey, userId, "1");
            }
            redisUtils.setExpire(likeKey, 24, TimeUnit.HOURS);
            //漫画的点赞量加一
            String comicsKey = ComicsConst.COMICS_REDIS_PRE + comicsId;
            redisUtils.hIncrBy(comicsKey, "comicsLike", 1);
            log.info("漫画:"+comicsId+"点赞成功");
            Long comicsLike = (Long) redisUtils.hGet(comicsKey, "comicsLike");
            return comicsLike;
        }
        return null;
    }

    /**
     * 用户取消点赞
     * @param comicsId
     * @param token
     */
    @Override
    public Long cancelLike(long comicsId, String token) {
        if (JWTUtils.validateJWT(token)) {
            String userId = JWTUtils.parseJWT(token).getSubject();
            //判断是否存在该用户
            userService.getUser(Long.parseLong(userId));
            //判断如果点赞过才能取消点赞
            String likeKey = ComicsIndexConst.LIKE_REDIS_PRE + comicsId;
            if (!redisUtils.hExists(likeKey, userId)) {
                log.info("用户:{}未点赞过漫画:{},无法取消点赞", userId, comicsId);
                throw new APIException("无法取消点赞");
            } else {
                log.info("用户:{}点赞成功漫画:{}", userId, comicsId);
                redisUtils.hDelete(likeKey, userId);
            }
            redisUtils.setExpire(likeKey, 24, TimeUnit.HOURS);
            //漫画的点赞量减一
            String comicsKey = ComicsConst.COMICS_REDIS_PRE + comicsId;
            redisUtils.hIncrBy(comicsKey, "comicsLike", -1);
            Long comicsLike = (Long) redisUtils.hGet(comicsKey, "comicsLike");
            log.info("用户:{}取消点赞漫画:{}成功", userId, comicsId);
            return comicsLike;
        }
        return null;
    }

    /**
     * 获取用户的浏览记录
     * @param token
     * @return
     */
    @Override
    public List<BrowseHistoryDTO> getHistory(String token) {
        if (JWTUtils.validateJWT(token)) {
            String userId = JWTUtils.parseJWT(token).getSubject();
            //判断是否存在该用户
            userService.getUser(Long.parseLong(userId));
            String historyKey = UserConst.USER_BROWSE_PRE + userId;
            if (!redisUtils.hasKey(historyKey)) {
                List<UserBrowseHistory> historyList = historyMapper.getHistory(Long.parseLong(userId), UserConst.USER_BROWSE_EXPIRE);
                for (UserBrowseHistory history : historyList) {
                    redisUtils.hPut(historyKey, history.getComicsId()+"", JSON.toJSONString(history));
                }
            }
            Map<Object, Object> historyMap = redisUtils.hGetAll(historyKey);
            List<BrowseHistoryDTO> list = new ArrayList<>();
            historyMap.forEach((key, value) -> {
                UserBrowseHistory history = JSON.parseObject(value + "", UserBrowseHistory.class);
                BrowseHistoryDTO historyDTO = new BrowseHistoryDTO();
                if (history.getDeleted() == 0 && belongDate(history.getGwtCreate(), new Date(), UserConst.USER_BROWSE_EXPIRE)) {
                    ComicsChapter chapter = comicsService.getChapter(history.getChapterId());
                    Comics comics = comicsService.getComics(chapter.getComicsId());
                    historyDTO.setChapterId(history.getChapterId());
                    historyDTO.setChapterNum(chapter.getChapterNum());
                    historyDTO.setComicsChapterNum(comics.getComicsChapterNum());
                    historyDTO.setComicsName(comics.getComicsName());
                    try {
                        historyDTO.setComicsCover(fastDFSUtils.getThumbImageTokenUrl(comics.getComicsCover()));
                    } catch (Exception e) {
                        log.error("漫画{}封面下载失败", comics.getComicsId());
                        throw new APIException("漫画封面下载失败");
                    }
                    list.add(historyDTO);
                } else {
                    redisUtils.hDelete(historyKey, key);
                }
            });
            redisUtils.setExpire(historyKey, 48, TimeUnit.HOURS);
            log.info("用户:{}请求历史记录成功", userId);
            return list;
        }
        return null;
    }

    /**
     * 删除历史记录
     * @param comicsId
     * @param token
     */
    @Override
    public void deleteHistory(long comicsId, String token) {
        if (JWTUtils.validateJWT(token)) {
            String userId = JWTUtils.parseJWT(token).getSubject();
            String historyKey = UserConst.USER_BROWSE_PRE + userId;
            String historyJson = (String) redisUtils.hGet(historyKey, comicsId+"");
            UserBrowseHistory history = JSON.parseObject(historyJson, UserBrowseHistory.class);
            history.setDeleted(1);
            System.out.println(history);
            redisUtils.hPut(historyKey, comicsId+"", JSON.toJSONString(history));
//            Map<Object, Object> historyMap = redisUtils.hGetAll(historyKey);
//            historyMap.forEach((key, value) -> {
//                UserBrowseHistory history = JSON.parseObject(value.toString(), UserBrowseHistory.class);
//                if (history.getComicsId() == comicsId) {
//                    history.setDeleted(1);
//                    redisUtils.hDelete(historyKey, key);
//                    redisUtils.hPut(historyKey, key.toString(), JSON.toJSONString(history));
//                }
//            });
        }
    }

    /**
     * 实现用户收藏漫画
     * @param comicsId
     * @param token
     */
    @Override
    public void collectComics(long comicsId, String token) {
        if (JWTUtils.validateJWT(token)) {
            String userId = JWTUtils.parseJWT(token).getSubject();
            //判断是否存在该用户
            userService.getUser(Long.parseLong(userId));
            //判断是否存在该漫画
            Comics comics = comicsService.getComics(comicsId);
            //将收藏记录存入缓存中
            String collectKey = UserConst.USER_COLLECT_PRE + userId;
            Map<String, Object> historyMap = new HashMap<>();
            historyMap.put("comicsId", comicsId);
            historyMap.put("comicsCover", comics.getComicsCover());
            historyMap.put("comicsName", comics.getComicsName());
            historyMap.put("deleted", 0);
            historyMap.put("gwtCreate", new Date());
            redisUtils.hPut(collectKey, comicsId+"", JSON.toJSONString(historyMap));
            redisUtils.setExpire(collectKey, 24, TimeUnit.HOURS);
            //漫画收藏量加一
            redisUtils.hIncrBy(ComicsConst.COMICS_REDIS_PRE+comicsId, "comicsCollect", 1);
        }
    }

    /**
     * 用户取消收藏
     * @param comicsId
     * @param token
     */
    @Override
    public void cancelCollect(long comicsId, String token) {
        if (JWTUtils.validateJWT(token)) {
            String userId = JWTUtils.parseJWT(token).getSubject();
            //判断是否存在该用户
            userService.getUser(Long.parseLong(userId));
            String collectKey = UserConst.USER_COLLECT_PRE + userId;
            if (redisUtils.hExists(collectKey, comicsId+"")) {
                redisUtils.hDelete(collectKey, comicsId+"");
                redisUtils.setExpire(collectKey, 36, TimeUnit.HOURS);
                redisUtils.set(UserConst.USER_CANCEL_COLLECT + userId + "_" + comicsId, "");
                //用户收藏量减一
                redisUtils.hIncrBy(ComicsConst.COMICS_REDIS_PRE+comicsId, "comicsCollect", -1);
            } else {
                log.info("用户:{}无相关收藏记录,无法取消收藏", userId);
                throw new APIException("取消收藏失败");
            }
        }
    }

    /**
     * 获取用户收藏漫画的列表
     * @param token
     * @return
     */
    @Override
    public List<CollectComicsDTO> getCollectList(String token) {
        if (JWTUtils.validateJWT(token)) {
            String userId = JWTUtils.parseJWT(token).getSubject();
            //判断是否存在该用户
            userService.getUser(Long.parseLong(userId));
            String collectKey = UserConst.USER_COLLECT_PRE + userId;
            List<CollectComicsDTO> list = new ArrayList<>();
            if (!redisUtils.hasKey(collectKey)) {
                QueryWrapper<ComicsCollect> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("user_id", userId);
                List<ComicsCollect> comicsCollects = collectMapper.selectList(queryWrapper);
                for (ComicsCollect comicsCollect : comicsCollects) {
                    CollectComicsDTO collectComicsDTO = new CollectComicsDTO();
                    Comics comics = comicsService.getComics(comicsCollect.getComicsId());
                    collectComicsDTO.setComicsId(comics.getComicsId());
                    collectComicsDTO.setComicsName(comics.getComicsName());
                    try {
                        collectComicsDTO.setComicsCover(fastDFSUtils.getThumbImageTokenUrl(comics.getComicsCover()));
                    } catch (Exception e) {
                        throw new APIException("获取封面失败");
                    }
                    redisUtils.hPut(collectKey, comics.getComicsId()+"", JSON.toJSONString(collectComicsDTO));
                    list.add(collectComicsDTO);
                }
                return list;
            } else {
                //从缓存中取出用户收藏的漫画列表
                Map<Object, Object> collectMap = redisUtils.hGetAll(collectKey);
                collectMap.forEach((key, value) -> {
                    CollectComicsDTO collectComicsDTO = JSON.parseObject(value.toString(), CollectComicsDTO.class);
                    try {
                        collectComicsDTO.setComicsCover(fastDFSUtils.getThumbImageTokenUrl(collectComicsDTO.getComicsCover()));
                    } catch (Exception e) {
                        throw new APIException("获取封面失败");
                    }
                    list.add(collectComicsDTO);
                });
                return list;
            }
        }
        return null;
    }

    /**
     * 判断创建历史记录的时间是否是在指定时间之内
     * @param time
     * @param now
     * @param n
     * @return
     */
    private boolean belongDate(Date time, Date now, int n) {
        Calendar calendar = Calendar.getInstance();  //得到日历
        calendar.setTime(now);//把当前时间赋给日历
        calendar.add(Calendar.DAY_OF_MONTH, -n);
        Date before7days = calendar.getTime();   //得到n前的时间
        if (before7days.getTime() < time.getTime()) {
            return true;
        } else {
            return false;
        }
    }
}
